package com.demarc.pesquisas.infraestrutura.util.utils;

import java.io.Serializable;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Collection;
import java.util.Date;

import javax.swing.text.MaskFormatter;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.primefaces.model.SortOrder;

import com.demarc.pesquisas.infraestrutura.persistencia.Filtro;

public class DemarPesquisasUtil implements Serializable {

    public static final int SCALE = 2;

    public static String formatarCpf(Object value) {
        return formatar("###.###.###-##", value);
    }

    public static String formatarCnpj(Object value) {
        return formatar("##.###.###/####-##", value);
    }

    public static String formatarCep(Object value) {
        return formatar("#####-###", value);
    }

    private static String formatar(String pattern, Object value) {
        MaskFormatter mask;
        try {
            mask = new MaskFormatter(pattern);
            mask.setValueContainsLiteralCharacters(false);
            return mask.valueToString(value);
        } catch (Throwable e) {
            throw new RuntimeException(e);
        }
    }

    public static Filtro adicionarOrdenacaoFiltro(Filtro filtro, int first, int pageSize,
            String sortField, SortOrder sortOrder) {

        filtro.setPrimeiroElemento(first);
        filtro.setQuantidadeMaximaResultados(pageSize);
        if (StringUtils.isNotEmpty(sortField)) {
            filtro.getOrdem().clear();
            filtro.adicionarOrdem(sortField, SortOrder.ASCENDING.equals(sortOrder));
        }
        return filtro;
    }

    /**
     * Valida se o objeto está nulo ou vazio.
     * 
     * @param object Objeto a ser validado.
     * 
     * @return TRUE caso o objeto esteha nulo ou vazio e FALSE caso o contrário.
     */
    public static boolean isNuloOuVazio(Object object) {
        boolean resultado = object == null;

        if (!resultado) {
            if (object instanceof String) {
                String temp = (String) object;
                resultado = StringUtils.isEmpty(temp);
            }
            if (object instanceof Collection<?>) {
                Collection<?> temp = (Collection<?>) object;
                resultado = temp.isEmpty();
            }
        }
        return resultado;
    }

    /**
     * Verifica se os objetos são todos NÃO nulos. Caso um único objeto seja nulo, é retornado
     * <code>false</code>.
     * 
     * @param objects Objetos a serem verificados.
     * @return <code>true</code> Caso todos os objetos não sejam nulos e <code>false</code> caso
     *         pelo menos um objeto seja nulo.
     */
    public static boolean isNaoNuloOuVazio(Object... objects) {
        boolean isNaoNuloOuVazio = true;
        for (Object object : objects) {
            if (isNuloOuVazio(object)) {
                isNaoNuloOuVazio = false;
                break;
            }
        }
        return isNaoNuloOuVazio;
    }

    /**
     * Verifica se algum dos objetos NÃO nulo. Caso um único objeto NÂO seja nulo, é retornado
     * <code>true</code>.
     * 
     * @param objects Objetos a serem verificados.
     * @return <code>true</code> Caso algum objeto NÃO seja nulo e <code>false</code> caso todos
     *         sejam nulos.
     */
    public static boolean isAlgumNaoNuloOuVazio(Object... objects) {
        boolean isNaoNuloOuVazio = false;
        for (Object object : objects) {
            if (isNaoNuloOuVazio(object)) {
                isNaoNuloOuVazio = true;
                break;
            }
        }
        return isNaoNuloOuVazio;
    }

    public static boolean isAlgumNuloOuVazio(Object... objects) {
        boolean isNuloOuVazio = false;
        for (Object object : objects) {
            if (isNuloOuVazio(object)) {
                isNuloOuVazio = true;
                break;
            }
        }
        return isNuloOuVazio;
    }

    /**
     * Verifica se os objetos são todos nulos. Caso um único objeto seja NÃO nulo, é retornado
     * <code>false</code>.
     * 
     * @param objects Objetos a serem verificados.
     * @return <code>true</code> Caso todos os objetos sejam nulos e <code>false</code> caso pelo
     *         menos um objeto seja n�o nulo.
     */
    public static boolean isTodosNuloOuVazio(Object... objects) {
        boolean isNuloOuVazio = true;
        for (Object object : objects) {
            if (isNaoNuloOuVazio(object)) {
                isNuloOuVazio = false;
                break;
            }
        }
        return isNuloOuVazio;
    }

    /**
     * Gera um novo codigo aleatório
     */
    public static String gerarNovoCodigo() {
        return String.valueOf(-new Date().getTime());
    }

    /**
     * Tenta transformar a string informada em numero e incrementa o valor em 1
     * 
     * @param codigo
     * @return (codigo + 1) ou 1 caso o codigo seja null ou não for um numero
     */
    public static String incrementarCodigo(String codigo) {
        String proximoCodigo = "1";
        if (StringUtils.isNotBlank(codigo) && StringUtils.isNumeric(codigo)) {
            proximoCodigo = String.valueOf(Long.valueOf(codigo.trim()) + 1);
        }
        return proximoCodigo;
    }

    /**
     * Tenta transformar a string informada em numero e incrementa o valor em 1
     * 
     * @param codigo
     * @return (codigo + 1) ou 1 caso o codigo seja null ou não for um numero
     */
    public static String incrementarCodigo(String codigo, int size) {
        String proximoCodigo = incrementarCodigo(codigo);
        return StringUtils.leftPad(proximoCodigo, size, ConstantesCaracteresUtil.ZERO_STRING);
    }

    /**
     * Executa o StringUtils.trimToEmpty e depois StringUtils.isNotBlank pra verificar se o
     * parâmetro é notBlank.
     * 
     * @param parametro String a ser verificada.
     */
    public static boolean isNotBlankWithTrim(String parametro) {
        return parametro == null ? false : StringUtils.isNotBlank(StringUtils
                .trimToEmpty(parametro));
    }

    /**
     * Replace caracters specials by string empty.
     * 
     * @param cpfCnpj CpfCnpj with caracters specials.
     * 
     * @return cpfCnpj CpfCnpj without caracters specials.
     */
    public static String replaceCaractersSpecialCpfCnpjByStringEmpty(String cpfCnpj) {
        if (cpfCnpj != null) {
            cpfCnpj =
                    StringUtils.replaceEachRepeatedly(cpfCnpj, new String[] {
                            ConstantesCaracteresUtil.PONTO, ConstantesCaracteresUtil.BARRA,
                            ConstantesCaracteresUtil.TRACO, ConstantesCaracteresUtil.SINAL_MAIS,
                            ConstantesCaracteresUtil.ABRE_PARENTESES,
                            ConstantesCaracteresUtil.FECHA_PARENTESES,
                            ConstantesCaracteresUtil.ESPACO_EM_BRANCO}, new String[] {
                            ConstantesCaracteresUtil.STRING_VAZIA,
                            ConstantesCaracteresUtil.STRING_VAZIA,
                            ConstantesCaracteresUtil.STRING_VAZIA,
                            ConstantesCaracteresUtil.STRING_VAZIA,
                            ConstantesCaracteresUtil.STRING_VAZIA,
                            ConstantesCaracteresUtil.STRING_VAZIA,
                            ConstantesCaracteresUtil.STRING_VAZIA});
        }
        return cpfCnpj;
    }

    public static BigDecimal calcularPercentual(BigDecimal valor, BigDecimal totalGeral) {

        BigDecimal pencentual = null;
        if (valor != null && totalGeral != null) {
            if (valor.compareTo(totalGeral) <= 0) {
                pencentual =
                        valor.multiply(new BigDecimal(100)).divide(totalGeral, SCALE,
                                RoundingMode.HALF_DOWN);
            } else {
                pencentual = null;
            }
        }
        return pencentual;
    }

    public static String obterPercentual(Object valor, Object totalGeral) {
        String percentual = "ERRO %";
        if (valor != null && totalGeral != null) {
            String valorString = valor.toString();
            String valorGeralString = totalGeral.toString();

            if (NumberUtils.isNumber(valorString) && NumberUtils.isNumber(valorGeralString)) {
                BigDecimal pencentualBigDecimal =
                        calcularPercentual(new BigDecimal(valorString), new BigDecimal(
                                valorGeralString));
                if (pencentualBigDecimal != null) {
                    percentual = pencentualBigDecimal.toString() + " %";
                }
            }
        }
        return percentual;
    }
}
